#!/bin/bash
#Author: YangYi
#Date: 2025-03-28
#Version: v1
#Content 一键诊断、处置原子能力，mater组件检测列表
#1.kube-apiserver
#2.kube-controller-manager
#3.kube-scheduler
#4.etcd
#5.calico-node
#6.nginx-ingress-controller
#7.docker/crictl
#8.集群证书有效期


# 检查是否传入了参数
if [ -z "$1" ]; then
  echo "Usage: $0 <请输入您需要诊断的节点IP: 10.145.xxx.xxx>"
  exit 1
fi
 
# 节点IP获取
IP=$1


# ---------------------------初始化全局变量----------------------------

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m'
 
# 组件配置（名称: 匹配模式,按实际部署修改）
declare -A COMPONENTS=(
    ["kube-apiserver"]="kube-apiserver"
    ["kube-controller-manager"]="kube-controller-manager"
    ["kube-scheduler"]="kube-scheduler"
    ["etcd"]="etcd"
    ["calico-node"]="calico-node"
    ["coredns"]="coredns" # 测试验证
    ["ingress-controller"]="nginx-ingress-controller"  
)
 
# 证书文件路径（按实际路径修改）
CERT_FILES=(
    "/etc/kubernetes/pki/apiserver.crt"
    "/etc/kubernetes/pki/ca.crt"
    "/etc/kubernetes/pki/front-proxy-ca.crt"
    "/etc/kubernetes/pki/etcd/server.crt"
    "/etc/kubernetes/pki/etcd/peer.crt"
    "/etc/kubernetes/pki/etcd/healthcheck-client.crt"
)

#全局返回值
CODE=""

# ----------------------------功能模块函数-----------------------------

# 检测容器运行时
get_container_runtime() {
    if command -v crictl &> /dev/null; then
        echo "crictl"
    elif command -v docker &> /dev/null; then
        echo "docker"
    else
        echo "Error: No container runtime found." >&2
        exit 1
    fi
}
 
# 检查组件状态
check_component_status() {
    local runtime=$1
    local component=$2
    local pattern=$3
    #echo "runtime: " $runtime
    #echo "component: " $component
    #echo "pattern: " $pattern
    
    local container_list
    if [ "$runtime" = "crictl" ]; then
        container_list=$(sudo crictl ps  --name "$pattern" -o json | jq -r '.status')
    else
        container_list=$(sudo docker ps  --filter "name=$pattern" --format "{{.Status}}")
    fi
 
    local running_count=0
    local total_count=0
    #echo "container_list: " $container_list 
 
    # 统计容器状态
    while IFS= read -r status; do
        ((total_count++))
        [[ $status == *"Up"* || $status == *"running"* ]] && ((running_count++))
    done <<< "$container_list"
 
    # 输出结果
    if [ "$total_count" -eq 0 ]; then
        echo -e "${RED}[FAIL] $component 未找到运行服务${NC}"
        return 1
    elif [ "$running_count" -eq "$total_count" ]; then
        echo -e "${GREEN}[OK] $component: $running_count/$total_count 服务运行中${NC}"
        return 0
    else
        echo -e "${RED}[FAIL] $component 异常: $running_count/$total_count 服务运行异常${NC}"
        return 1
    fi
}
 
# 检查证书有效期
check_certificate_expiry() {
    local cert_path=$1
    
    if [ ! -f "$cert_path" ]; then
        echo -e "${YELLOW}[WARN] 证书文件 $cert_path 不存在${NC}"
        return
    fi
 
    local expiry_date=$(openssl x509 -in "$cert_path" -noout -dates 2>/dev/null | awk '/notAfter/' | awk -F= '{print $2}')
    
    if [ -z "$expiry_date" ]; then
        echo -e "${RED}[ERROR] 无法解析证书 $cert_path 的有效期${NC}"
        return
    fi
 
    # 计算剩余天数
    local expiry_timestamp=$(date -d "$expiry_date" +%s 2>/dev/null)
    local current_timestamp=$(date +%s)
    
    if [ -z "$expiry_timestamp" ]; then
        echo -e "${RED}[ERROR] 无效的证书过期日期格式: $expiry_date${NC}"
        return
    fi
 
    local remaining_days=$(( (expiry_timestamp - current_timestamp) / 86400 ))
 
    echo -e "证书: $cert_path"
    echo -e "过期日期: $expiry_date"
    echo -e "剩余天数: ${GREEN}$remaining_days 天${NC}"
 
    if [ "$remaining_days" -lt 3650 ]; then  # 验证证书报错10年,正常为30天
        echo -e "${RED}[警告] 证书将在3650天内过期！${NC}"
    #if [ "$remaining_days" -lt 30 ]; then  # 验证证书报错10年,正常为30天
    #    echo -e "${RED}[警告] 证书将在30天内过期！${NC}"
    elif [ "$remaining_days" -lt 90 ]; then
        echo -e "${YELLOW}[注意] 证书将在90天内过期${NC}"
    fi
    echo
}
 
# 主检查函数
main_check() {
    local runtime=$(get_container_runtime)
    local all_ok=0
 
    echo -e "\n${YELLOW}=== Master组件状态检查 ===${NC}"
    echo "-------------------------------------------------"
    for component in "${!COMPONENTS[@]}"; do      # 循环所有实例验证
        check_component_status "$runtime" "$component" "${COMPONENTS[$component]}" || all_ok=1
    done
 
    echo -e "\n${YELLOW}=== 证书有效期检查 ===${NC}"
    echo "-----------------------------------------"
    for cert in "${CERT_FILES[@]}"; do
        check_certificate_expiry "$cert" || all_ok=1
    done
 
    return $all_ok
}
 
# 执行主程序,根据返all_ok回值判断全局结果
if main_check; then
    CODE=200	
    echo -e "\n${GREEN}$CODE 所有检查通过！${NC}"
    exit 0
else
    CODE=1000	
    echo -e "\n${RED}$CODE 发现异常，请检查输出详情！${NC}"
    exit 1
fi


